package com.google.code.opengw.server.domain;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;

import com.google.code.opengw.support.OpenGWException;

public class WorkerPool {
	private int poolSize;
    private int poolIncreamentCount;
    private int maxPoolSizeLimit;
    private ConnectionQueue connectionQueue;
    private List<Worker> workerPool;
    private Queue<Worker> avaliableWorkerQueue;
    
    public WorkerPool(int poolSize, int poolIncreamentCount, 
    		int maxPoolSizeLimit, ConnectionQueue connectionQueue) {
    	workerPool    = new ArrayList<Worker>();
    	avaliableWorkerQueue = new LinkedList<Worker>();
    	this.connectionQueue = connectionQueue;
        this.poolSize = poolSize;
        this.poolIncreamentCount = poolIncreamentCount;
        this.maxPoolSizeLimit = maxPoolSizeLimit;
    }
    
    public synchronized Worker getWorker(){
    	if(connectionQueue.isEmpty() || avaliableWorkerQueue.isEmpty())
    		throw new NoSuchElementException();
    	Worker worker = avaliableWorkerQueue.poll();
    	worker.setSocket(connectionQueue.getConnection());
    	return worker;
    	
    }
    
    public synchronized void avaliableWorker(Worker worker){
    	avaliableWorkerQueue.add(worker);
    }
    
    /**
     * Method description
     *
     *
     * @param worker
     *
     * @throws OpenGWException
     */
    public synchronized void addWorker(Worker worker) throws OpenGWException {
        if (workerPool.size() < poolSize) {
        	workerPool.add(worker);
        	avaliableWorkerQueue.add(worker);
        } else {
            throw new OpenGWException(OpenGWException.POOL_LIMIT_EXCEED);
        }
    }   
    
    public int increasePoolSize(){
		if(poolSize < maxPoolSizeLimit){
			int newPoolSize = poolSize;
			newPoolSize += poolIncreamentCount;
			if(newPoolSize > maxPoolSizeLimit)
				newPoolSize = maxPoolSizeLimit;
			int diff = newPoolSize - poolSize;
			poolSize = newPoolSize;
			return diff;
		}
		return 0;
    }
    
    public boolean isAvaliableConnection(){
    	return !connectionQueue.isEmpty();
    }
    
    public boolean isAvaliableWorker(){
    	return !avaliableWorkerQueue.isEmpty();
    }
    
    public boolean isPoolSizeIncrementNeed(){
    	return poolSize  < connectionQueue.size() && poolSize < maxPoolSizeLimit;
    }
    
    public int getPoolSize(){
    	return poolSize;
    }
    
    public int getAvaliableWorkerCount(){
    	return avaliableWorkerQueue.size();
    }
    
}
